package com.mini.mybatis.binding;

import com.mini.mybatis.session.Configuration;
import com.mini.mybatis.session.SqlSession;

import java.util.HashMap;
import java.util.Map;

/**
 * 映射器注册表 - 管理所有的Mapper接口
 */
public class MapperRegistry {
    
    private final Configuration config;
    
    /**
     * 存储映射器代理工厂
     * key: Mapper接口类型
     * value: 对应的代理工厂
     */
    private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
    
    public MapperRegistry(Configuration config) {
        this.config = config;
    }
    
    /**
     * 获取映射器实例
     * @param type Mapper接口类型
     * @param sqlSession SQL会话
     * @return 映射器代理实例
     */
    @SuppressWarnings("unchecked")
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new RuntimeException("类型 " + type + " 未在映射器注册表中注册");
        }
        
        try {
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception e) {
            throw new RuntimeException("创建映射器实例失败: " + type, e);
        }
    }
    
    /**
     * 检查是否包含指定的映射器
     * @param type Mapper接口类型
     * @return 是否包含
     */
    public <T> boolean hasMapper(Class<T> type) {
        return knownMappers.containsKey(type);
    }
    
    /**
     * 添加映射器
     * @param type Mapper接口类型
     */
    public <T> void addMapper(Class<T> type) {
        // 必须是接口
        if (type.isInterface()) {
            if (hasMapper(type)) {
                throw new RuntimeException("类型 " + type + " 已经在映射器注册表中注册");
            }
            
            boolean loadCompleted = false;
            try {
                knownMappers.put(type, new MapperProxyFactory<>(type));
                loadCompleted = true;
            } finally {
                if (!loadCompleted) {
                    knownMappers.remove(type);
                }
            }
        }
    }
    
    /**
     * 获取所有已知的映射器
     */
    public Map<Class<?>, MapperProxyFactory<?>> getKnownMappers() {
        return knownMappers;
    }
}